<?php

/**
 * Albireo Kernel
 *
 * @copyright  Copyright (c) 2010 Albireo Solutions
 * @package    Kernel
 */

namespace Albireo\Application;

use Nette\Object;
use Albireo\Application\Application;
use Albireo\Application\NotAllowedApplicationException;
use \dibi;
use \InvalidArgumentException;
use Nette\Collections\ArrayList;
use Nette\Web\User;
use Celebrio\AccessControl\AlbireoUser;
use Nette\Environment;

/**
 * TODO: need to change db entity according to this object
 * also doesnt react on "system" setting
 *
 */
class ApplicationManager extends Object {
    const APPSUSERS = "applications_users";
    const APPSUSERS_USER = "id_user";

    const APP = "applications";

    const APP_TR = "applications_translations";

    const APP_ID = "id_application";
    const APP_URL = "url";
    const APP_NAME = "name";
    const APP_PUBLISHER = "publisher";
    const APP_ALTTEXT = "altText";
    const APP_CREATED = "created";
    const APP_VERSION = "version";
    const APP_SYSTEM = "system";
    const APP_AUTO = "autoinstall";

    const APP_TR_TITLE = "title";
    const APP_TR_LANGUAGE = "language";

    /**
     * @var Nette\Web\User;
     */
    private $user;

    /**
     * @param  Nette\Web\User $user
     */
    public function __construct($user) {
        $this->user = $user;
    }

    public function getApplications() {

        $res = dibi::query("SELECT " . self::APP_ID . ", " . self::APP_URL . ", " . self::APP_NAME . ", " . self::APP_PUBLISHER . ", " . self::APP_SYSTEM . ",
        " . self::APP_ALTTEXT . ", " . self::APP_CREATED . ", " . self::APP_VERSION . ", " . self::APP_AUTO . " FROM [" . self::APP . "]");
        return $this->buildApps($res);
    }

    private function buildApps($res) {
        $apps = new ArrayList();
        foreach ($res as $n => $row) {
            $app = new Application($row[self::APP_NAME], $row[self::APP_URL]);
            $app->setAltText($row[self::APP_ALTTEXT]);
            $app->setCreated($row[self::APP_CREATED]);
            $app->setId($row[self::APP_ID]);
            $app->setPublisher($row[self::APP_PUBLISHER]);
            $app->setVersion($row[self::APP_VERSION]);
            $app->setSystem($row[self::APP_SYSTEM]);
            $app->setAuto($row[self::APP_AUTO]);
            $app->setTitle($row[self::APP_TR_TITLE]);
            $apps->append($app);
        }
        return $apps;
    }

    /**
     * @param Albireo\Application\Application $app
     */
    public function addApplication(Application $app) {
        if (is_null($app->getName()) || is_null($app->getUrl())) {
            throw new InvalidArgumentException(_("Application must have name and url"));
        }
        dibi::begin();
        dibi::query("INSERT INTO [" . self::APP . "]", array(
            self::APP_URL => $app->getUrl(),
            self::APP_NAME => $app->getName(),
            self::APP_PUBLISHER => $app->getPublisher(),
            self::APP_ALTTEXT => $app->getAltText(),
            self::APP_CREATED => new \Datetime(),
            self::APP_SYSTEM => $app->getSystem(),
            self::APP_VERSION => $app->getVersion(),
            self::APP_AUTO => $app->getAuto()
        ));

        $lastId = dibi::getInsertId();
        $trans = array();
        $trans[self::APP_ID] = array();
        $trans[self::APP_TR_LANGUAGE] = array();
        $trans[self::APP_TR_TITLE] = array();

        foreach ($app->getTranslations() as $key => $value) {
            $trans[self::APP_ID][] = $lastId;
            $trans[self::APP_TR_LANGUAGE][] = $key;
            $trans[self::APP_TR_TITLE][] = $value;
        }

        dibi::query("INSERT INTO [" . self::APP_TR . "] %m", $trans);
        dibi::commit();
    }

    /**
     * @param Albireo\Application\Application $app
     * @return void
     */
    public function updateApplication(Application $app) {
        return dibi::query("UPDATE [" . self::APP . "] SET %a WHERE " . self::APP_ID . " = %i OR " . self::APP_NAME . " = %s", array(
                    self::APP_NAME => $app->getName(),
                    self::APP_URL => $app->getUrl(),
                    self::APP_PUBLISHER => $app->getPublisher(),
                    self::APP_ALTTEXT => $app->getAltText(),
                    self::APP_VERSION => $app->getVersion(),
                    self::APP_SYSTEM => $app->getSystem(),
                    self::APP_AUTO => $app->getAuto()
                        ), $app->getId(), $app->getName());
    }

    /**
     * @param Albireo\Application\Application $app
     * @return void
     */
    public function removeApplication(Application $app) {
        return dibi::query("DELETE FROM [" . self::APP . "] WHERE " . self::APP_ID . " = %i OR " . self::APP_NAME . " = %s", $app->getId(), $app->getName());
    }

    /**
     * Gets application by name but only when the app is allowed
     *
     * @param String $name
     * @return Albireo\Application\Application
     */
    private function getApplicationDataSource() {
        $lang = Environment::getVariable("lang");
        $query = dibi::select(self::APP . "." . self::APP_ID)->select(self::APP_URL)->select(self::APP_NAME)->select(self::APP_PUBLISHER)->select(self::APP_SYSTEM)
        ->select(self::APP_ALTTEXT)->select(self::APP_CREATED)->select(self::APP_VERSION)->select(self::APP_AUTO)->select(self::APP_TR_TITLE)
        ->from(self::APP)->join(self::APP_TR)
        ->on(self::APP_TR . '.' . self::APP_ID . ' = ' . self::APP . '.' . self::APP_ID)
        ->where(self::APP_TR_LANGUAGE . ' = "' . $lang . '"');
        return $query;
   }

    public function getApplicationByName($name) {
        $row = $this->getApplicationDataSource()->where(self::APP_NAME . "=%s", $name)->fetch();
        if ($row) {
            return $this->buildApplication($row);
        } else {
            throw new NotAllowedApplicationException(_("Application not installed or not allowed for a current user"));
        }
    }

    public function getApplicationsForUser() {
        $rows = $this->getApplicationDataSource()->leftJoin(self::APPSUSERS)
                        ->on(self::APPSUSERS . '.' . self::APP_ID . ' = ' . self::APP . '.' . self::APP_ID)
                        ->where("(".self::APPSUSERS_USER." = %i OR ".self::APP_AUTO." = %b )", $this->user->getIdentity()->data["id"], true)
                        ->fetchAll();
        return $this->buildApps($rows);
    }

    private function buildApplication($row) {
        $app = new Application($row[self::APP_NAME], $row[self::APP_URL]);
        $app->setAltText($row[self::APP_ALTTEXT]);
        $app->setCreated($row[self::APP_CREATED]);
        $app->setId($row[self::APP_ID]);
        $app->setPublisher($row[self::APP_PUBLISHER]);
        $app->setVersion($row[self::APP_VERSION]);
        $app->setSystem($row[self::APP_SYSTEM]);
        $app->setAuto($row[self::APP_AUTO]);
        $app->setTitle($row[self::APP_TR_TITLE]);
        return $app;
    }

    /**
     * @param Albireo\Application\Application $app
     * @param Kernel\AlbireoUser $usr
     */
    public function addApplicationToUser(Application $app, AlbireoUser $usr = null) {
        if ($usr == null) {
            $id = $this->user->getIdentity()->data["id"];
        } else {
            $id = $usr->getId();
        }
        return dibi::query("INSERT INTO [" . self::APPSUSERS . "](
        " . self::APPSUSERS_USER . ",
        " . self::APP_ID . "
        ) VALUES
        (%iN,%iN)", $id, $app->getId());
    }

    /**
     * @param Albireo\Application\Application $app
     * @param Kernel\AlbireoUser $usr
     */
    public function deleteApplicationFromUser(Application $app, AlbireoUser $usr = null) {
        if ($usr == null) {
            $id = $this->user->getIdentity()->data["id"];
        } else {
            $id = $usr->getId();
        }
        return dibi::query("DELETE FROM [" . self::APPSUSERS . "] WHERE " . self::APPSUSERS_USER . "=%i AND " . self::APP_ID . "=%i", $id, $app->getId());
    }
}